import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.charset.Charset;
import org.apache.http.HttpEntity;
import org.apache.http.HttpStatus;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import java.util.Arrays;

import com.google.gson.Gson;

import com.iplusbot.api.Err;
import com.iplusbot.api.Robot;
import com.iplusbot.api.Mission;
import com.iplusbot.api.MissionStep;
import com.iplusbot.api.MissionCommand;

public class App {
    private String _addr;
    private CloseableHttpClient _client;

    public App(String addr) {
        _addr = addr;
        _client = HttpClients.createDefault();
    }

    private static <T> T readJsonObject(InputStream in, Class<T> type) {
        Gson gson = new Gson();
        InputStreamReader  r = new InputStreamReader(in);
        T result = gson.fromJson(r, type);
        return result;
    } 

    public void queryRobotsInfo() throws Exception {
        HttpGet req = new HttpGet(_addr+"/api/v1/robots");
        CloseableHttpResponse resp = _client.execute(req);
        try {
            HttpEntity entity = resp.getEntity();
            if (resp.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
                Robot[] robs = readJsonObject(entity.getContent(), Robot[].class);
                for (Robot r : robs) {
                    System.out.println(r);
                }
            } else {
                Err err = readJsonObject(entity.getContent(), Err.class);
                System.out.println(err);
            }
        } catch (Exception e) {
            System.out.println(e);
        } finally {
            resp.close();
        }
    }

    public void queryRobotInfo(int id) throws Exception {
        HttpGet req = new HttpGet(_addr+"/api/v1/robots/"+id);
        CloseableHttpResponse resp = _client.execute(req);
        try {
            HttpEntity entity = resp.getEntity();
            if (resp.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
                Robot r = readJsonObject(entity.getContent(), Robot.class);
                System.out.println(r);
            } else {
                Err err = readJsonObject(entity.getContent(), Err.class);
                System.out.println(err);
            }
        } catch (Exception e) {
            System.out.println(e);
        } finally {
            resp.close();
        }
    }

    public long createMission(String uuid, String mapname, int[] targets, String[] actions) throws Exception {
        Mission m = new Mission();
        m.setRefUuid(uuid);
        MissionStep[] steps = new MissionStep[targets.length];
        for (int i = 0; i < targets.length; i++) {
            steps[i] = new MissionStep();
            steps[i].setMapName(mapname);
            steps[i].setTarget(targets[i]);
            steps[i].setAction(actions[i]);
        }
        m.setSteps(steps);
        Gson gson = new Gson();

        HttpPost req = new HttpPost(_addr+"/api/v1/missions");
        StringEntity ent = new StringEntity(gson.toJson(m), Charset.forName("UTF-8"));
        ent.setContentEncoding("UTF-8");
        ent.setContentType("application/json");
        req.setHeader("Content-type", "application/json; charset=utf-8");
        req.setEntity(ent);
        CloseableHttpResponse resp = _client.execute(req);
        try {
            HttpEntity entity = resp.getEntity();
            if (resp.getStatusLine().getStatusCode() == HttpStatus.SC_CREATED) {
                m = readJsonObject(entity.getContent(), Mission.class);
                System.out.println(m);
            } else {
                Err err = readJsonObject(entity.getContent(), Err.class);
                System.out.println(err);
            }
        } catch (Exception e) {
            System.out.println(e);
        } finally {
            resp.close();
        }
        return m.getId();
    }

    public void queryMissionInfo(long mid) throws Exception {
        HttpGet req = new HttpGet(_addr+"/api/v1/missions/"+mid);
        CloseableHttpResponse resp = _client.execute(req);
        try {
            HttpEntity entity = resp.getEntity();
            if (resp.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
                Mission m = readJsonObject(entity.getContent(), Mission.class);
                System.out.println(m);
            } else {
                Err err = readJsonObject(entity.getContent(), Err.class);
                System.out.println(err);
            }
        } catch (Exception e) {
            System.out.println(e);
        } finally {
            resp.close();
        }
    }

    public void queryMissionInfoByUuid(String uuid) throws Exception {
        HttpGet req = new HttpGet(_addr+"/api/v1/uuid/missions/"+uuid);
        CloseableHttpResponse resp = _client.execute(req);
        try {
            HttpEntity entity = resp.getEntity();
            if (resp.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
                Mission m = readJsonObject(entity.getContent(), Mission.class);
                System.out.println(m);
            } else {
                Err err = readJsonObject(entity.getContent(), Err.class);
                System.out.println(err);
            }
        } catch (Exception e) {
            System.out.println(e);
        } finally {
            resp.close();
        }
    }

    public void cancelMission(String uuid) throws Exception {
        MissionCommand mc = new MissionCommand();
        mc.setCmd(MissionCommand.CMD_CANCEL);
        mc.setMissionUuid(uuid);
        Gson gson = new Gson();

        HttpPost req = new HttpPost(_addr+"/api/v1/mscmds");
        StringEntity ent = new StringEntity(gson.toJson(mc), Charset.forName("UTF-8"));
        ent.setContentEncoding("UTF-8");
        ent.setContentType("application/json");
        req.setHeader("Content-type", "application/json; charset=utf-8");
        req.setEntity(ent);
        CloseableHttpResponse resp = _client.execute(req);
        try {
            HttpEntity entity = resp.getEntity();
            if (resp.getStatusLine().getStatusCode() == HttpStatus.SC_CREATED) {
                mc = readJsonObject(entity.getContent(), MissionCommand.class);
                System.out.println(mc);
            } else {
                Err err = readJsonObject(entity.getContent(), Err.class);
                System.out.println(err);
            }
        } catch (Exception e) {
            System.out.println(e);
        } finally {
            resp.close();
        }
    }

    public static void main(String[] args) {
        String addr = "http://127.0.0.1:8858";
        try {
            if (args.length > 0) {
                addr = args[0];
            }
            System.out.printf("connect to server at %s\n", addr);
            App app = new App(addr);
            app.queryRobotsInfo();
            app.queryRobotInfo(1);
            app.queryRobotInfo(4);
            String uuid = "yyy-1234";
            long mid = app.createMission(uuid, "test", new int[]{1,2,3}, new String[]{"load", "unload", "charge"});
            if (mid != 0 ) {
                app.queryMissionInfo(mid);
            }
            app.cancelMission(uuid);
            app.queryMissionInfoByUuid(uuid);
        } catch (Exception e) {
            System.out.println(e);
            System.out.println(Arrays.toString(e.getStackTrace()));
        }
    }
}
